home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / sox / voc.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  7KB  |  301 lines

  1. /*
  2.  * July 5, 1991
  3.  * Copyright 1991 Lance Norskog And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Lance Norskog And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * Sound Tools Sound Blaster VOC handler sources.
  12.  *
  13.  * Outstanding problem: the Sound Blaster DMA clock is 8 bits wide,
  14.  * giving spotty resolution above 10khz.  voctartwrite() should check
  15.  * the given output rate and make sure it's +-1% what the SB can
  16.  * actually do.  Other format drivers should do similar checks.
  17.  */
  18.  
  19. #include "st.h"
  20.  
  21. /* Private data for VOC file */
  22. typedef struct vocstuff {
  23.     long    rest;            /* bytes remaining in current block */
  24.     long    rate;            /* rate code (byte) of this chunk */
  25.     int    silent;            /* sound or silence? */
  26.     long    srate;            /* rate code (byte) of silence */
  27.     int    blockseek;        /* start of current output block */
  28.     long    samples;        /* number of samples output */
  29. } *vs_t;
  30.  
  31. #define    VOC_TERM    0
  32. #define    VOC_DATA    1
  33. #define    VOC_CONT    2
  34. #define    VOC_SILENCE    3
  35. #define    VOC_MARKER    4
  36. #define    VOC_TEXT    5
  37. #define    VOC_LOOP    6
  38. #define    VOC_LOOPEND    7
  39.  
  40. #define    min(a, b)    (((a) < (b)) ? (a) : (b))
  41.  
  42. IMPORT int summary, verbose;
  43. void getblock();
  44.  
  45. vocstartread(ft) 
  46. ft_t ft;
  47. {
  48.     char header[20];
  49.     vs_t v = (vs_t) ft->priv;
  50.     int sbseek;
  51.  
  52.     if (! ft->seekable)
  53.         fail("VOC input file must be a file, not a pipe");
  54.     if (fread(header, 1, 20, ft->fp) != 20)
  55.         fail("unexpected EOF in VOC header");
  56.     if (strncmp(header, "Creative Voice File\032", 19))
  57.         fail("VOC file header incorrect");
  58.  
  59.     sbseek = rlshort(ft);
  60.     fseek(ft->fp, sbseek, 0);
  61.  
  62.     v->rate = -1;
  63.     v->rest = 0;
  64.     getblock(ft);
  65.     if (v->rate == -1)
  66.         fail("Input .voc file had no sound!");
  67.  
  68.     ft->info.rate = 1000000.0/(256 - v->rate);
  69.     ft->info.size = BYTE;
  70.     ft->info.style = UNSIGNED;
  71.     if (ft->info.channels == -1)
  72.         ft->info.channels = 1;
  73. }
  74.  
  75. vocread(ft, buf, len) 
  76. ft_t ft;
  77. long *buf, len;
  78. {
  79.     vs_t v = (vs_t) ft->priv;
  80.     int done = 0;
  81.     
  82.     if (v->rest == 0)
  83.         getblock(ft);
  84.     if (v->rest == 0)
  85.         return 0;
  86.  
  87.     if (v->silent) {
  88.         /* Fill in silence */
  89.         for(;v->rest && (done < len); v->rest--, done++)
  90.             *buf++ = 0x80000000;
  91.     } else {
  92.         for(;v->rest && (done < len); v->rest--, done++) {
  93.             long l;
  94.             if ((l = getc(ft->fp)) == EOF) {
  95.                 fail("VOC input: short file"); /* */
  96.                 v->rest = 0;
  97.                 return 0;
  98.             }
  99.             l ^= 0x80;    /* convert to signed */
  100.             *buf++ = LEFT(l, 24);
  101.         }
  102.     }
  103.     return done;
  104. }
  105.  
  106. /* nothing to do */
  107. vocstopread(ft) 
  108. ft_t ft;
  109. {
  110. }
  111.  
  112. vocstartwrite(ft) 
  113. ft_t ft;
  114. {
  115.     vs_t v = (vs_t) ft->priv;
  116.  
  117.     if (! ft->seekable)
  118.         fail("Output .voc file must be a file, not a pipe");
  119.  
  120.     v->samples = 0;
  121.  
  122.     /* File format name and a ^Z (aborts printing under DOS) */
  123.     (void) fwrite("Creative Voice File\032\032", 1, 20, ft->fp);
  124.     wlshort(ft, 26);            /* size of header */
  125.     wlshort(ft, 0x10a);                     /* major/minor version number */
  126.     wlshort(ft, 0x1129);            /* checksum of version number */
  127.  
  128.     ft->info.size = BYTE;
  129.     ft->info.style = UNSIGNED;
  130.     if (ft->info.channels == -1)
  131.         ft->info.channels = 1;
  132. }
  133.  
  134. vocwrite(ft, buf, len) 
  135. ft_t ft;
  136. long *buf, len;
  137. {
  138.     vs_t v = (vs_t) ft->priv;
  139.     unsigned char uc;
  140.  
  141.     v->rate = 256 - (1000000.0/(float)ft->info.rate);    /* Rate code */
  142.     if (v->samples == 0) {
  143.         /* No silence packing yet. */
  144.         v->silent = 0;
  145.         blockstart(&outformat);
  146.     }
  147.     v->samples += len;
  148.     while(len--) {
  149.         uc = RIGHT(*buf++, 24);
  150.         uc ^= 0x80;
  151.         putc(uc, ft->fp);
  152.     }
  153. }
  154.  
  155. vocstopwrite(ft) 
  156. ft_t ft;
  157. {
  158.     blockstop(ft);
  159. }
  160.  
  161. /* Voc-file handlers */
  162.  
  163. /* Read next block header, save info, leave position at start of data */
  164. void
  165. getblock(ft)
  166. ft_t ft;
  167. {
  168.     vs_t v = (vs_t) ft->priv;
  169.     unsigned char uc, block;
  170.     unsigned long sblen;
  171.     int i;
  172.  
  173.     v->silent = 0;
  174.     while (v->rest == 0) {
  175.         if (feof(ft->fp))
  176.             return;
  177.         block = getc(ft->fp);
  178.         if (block == VOC_TERM)
  179.             return;
  180.         if (feof(ft->fp))
  181.             return;
  182.         uc = getc(ft->fp);
  183.         sblen = uc;
  184.         uc = getc(ft->fp);
  185.         sblen |= ((long) uc) << 8;
  186.         uc = getc(ft->fp);
  187.         sblen |= ((long) uc) << 16;
  188.         switch(block) {
  189.         case VOC_DATA: 
  190.             uc = getc(ft->fp);
  191.             if (uc == 0)
  192.                fail("File %s: Sample rate is zero?");
  193.             if ((v->rate != -1) && (uc != v->rate))
  194.                fail("File %s: sample rate codes differ: %d != %d",
  195.                     v->rate, uc);
  196.             v->rate = uc;
  197.             uc = getc(ft->fp);
  198.             if (uc != 0)
  199.                 fail("File %s: only interpret 8-bit data!");
  200.             v->rest = sblen - 2;
  201.             return;
  202.         case VOC_CONT: 
  203.             v->rest = sblen;
  204.             return;
  205.         case VOC_SILENCE: 
  206.             {
  207.             unsigned short period;
  208.  
  209.             period = rlshort(ft);
  210.             uc = getc(ft->fp);
  211.             if (uc == 0)
  212.                 fail("File %s: Silence sample rate is zero");
  213.             /* 
  214.              * Some silence-packed files have gratuitously
  215.              * different sample rate codes in silence.
  216.              * Adjust period.
  217.              */
  218.             if ((v->rate != -1) && (uc != v->rate))
  219.                 period = (period * (256 - uc))/(256 - v->rate);
  220.             else
  221.                 v->rate = uc;
  222.             v->rest = period;
  223.             v->silent = 1;
  224.             return;
  225.             }
  226.         case VOC_MARKER:
  227.             uc = getc(ft->fp);
  228.             uc = getc(ft->fp);
  229.             /* Falling! Falling! */
  230.         case VOC_TEXT:
  231.             {
  232.             int i;
  233.             /* Could add to comment in SF? */
  234.             for(i = 0; i < sblen; i++)
  235.                 getc(ft->fp);
  236.             }
  237.             continue;    /* get next block */
  238.         case VOC_LOOP:
  239.         case VOC_LOOPEND:
  240.             report("File %s: skipping repeat loop");
  241.             for(i = 0; i < sblen; i++)
  242.                 getc(ft->fp);
  243.             break;
  244.         default:
  245.             report("File %s: skipping unknown block code %d",
  246.                 ft->filename, block);
  247.             for(i = 0; i < sblen; i++)
  248.                 getc(ft->fp);
  249.         }
  250.     }
  251. }
  252.  
  253. /* Start an output block. */
  254. blockstart(ft)
  255. ft_t ft;
  256. {
  257.     vs_t v = (vs_t) ft->priv;
  258.  
  259.     v->blockseek = ftell(ft->fp);
  260.     if (v->silent) {
  261.         putc(VOC_SILENCE, ft->fp);    /* Silence block code */
  262.         putc(0, ft->fp);        /* Period length */
  263.         putc(0, ft->fp);        /* Period length */
  264.         putc((int) v->rate, ft->fp);        /* Rate code */
  265.     } else {
  266.         putc(VOC_DATA, ft->fp);        /* Voice Data block code */
  267.         putc(0, ft->fp);        /* block length (for now) */
  268.         putc(0, ft->fp);        /* block length (for now) */
  269.         putc(0, ft->fp);        /* block length (for now) */
  270.         putc((int) v->rate, ft->fp);        /* Rate code */
  271.         putc(0, ft->fp);        /* 8-bit raw data */
  272.     }
  273. }
  274.  
  275. /* End the current data or silence block. */
  276. blockstop(ft) 
  277. ft_t ft;
  278. {
  279.     vs_t v = (vs_t) ft->priv;
  280.     long datum;
  281.  
  282.     putc(0, ft->fp);            /* End of file block code */
  283.     fseek(ft->fp, v->blockseek, 0);        /* seek back to block length */
  284.     fseek(ft->fp, 1, 1);            /* seek forward one */
  285.     if (v->silent) {
  286.         datum = (v->samples) & 0xff;
  287.         putc((int)datum, ft->fp);       /* low byte of length */
  288.         datum = (v->samples >> 8) & 0xff;
  289.         putc((int)datum, ft->fp);  /* high byte of length */
  290.     } else {
  291.         v->samples += 2;        /* adjustment: SBDK pp. 3-5 */
  292.         datum = (v->samples) & 0xff;
  293.         putc((int)datum, ft->fp);       /* low byte of length */
  294.         datum = (v->samples >> 8) & 0xff;
  295.         putc((int)datum, ft->fp);  /* middle byte of length */
  296.         datum = (v->samples >> 16) & 0xff;
  297.         putc((int)datum, ft->fp); /* high byte of length */
  298.     }
  299. }
  300.  
  301.